package com.kz;

import com.kz.entity.sys.ShiroAuthoritySetting;
import com.kz.realm.MyShiroRealm;
import com.kz.userservice.ShiroAuthoritySettingRpcService;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.cas.CasFilter;
import org.apache.shiro.cas.CasSubjectFactory;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.filter.authc.LogoutFilter;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.filter.DelegatingFilterProxy;
import tools.util.ConfigTool;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Shiro集成Cas配置
 *
 * @author kz
 */
@Configuration
public class ShiroCasConfiguration {

    private static final Logger logger = LoggerFactory.getLogger(ShiroCasConfiguration.class);

    /**
     * 项目代号
     */
    public static String appCode = ConfigTool.getProp("shiro.appCode");
    /**
     * 项目地址
     */
    public static String shiroServerUrlPrefix = ConfigTool.getProp("shiro.shiroServerUrlPrefix");

    public static String unauthorizedUrl = ConfigTool.getProp("shiro.unauthorizedUrl");

    /**
     * 统一前置地址
     */
    public static final String casServerUrlPrefix = "http://127.0.0.1:81";
    /**
     * Cas登录页面地址
     */
    public static final String casLoginUrl = casServerUrlPrefix + "/login";
    /**
     * Cas登出页面地址
     */
    public static final String casLogoutUrl = casServerUrlPrefix + "/logout";

    /**
     * casFilter UrlPattern
     */
    public static final String casFilterUrlPattern = "/shiro-cas";
    /**
     * 登录后返回项目
     */
    public static final String loginUrl = casLoginUrl + "?service=" + shiroServerUrlPrefix + casFilterUrlPattern;

    /**
     * 设置缓存配置
     *
     * @return
     */
    @Bean
    public EhCacheManager getEhCacheManager() {
        EhCacheManager em = new EhCacheManager();
        em.setCacheManagerConfigFile("classpath:ehcache-shiro.xml");
        return em;
    }

    @Bean(name = "myShiroCasRealm")
    public MyShiroRealm myShiroCasRealm(EhCacheManager cacheManager) {
        MyShiroRealm realm = new MyShiroRealm();
        realm.setCacheManager(cacheManager);
        return realm;
    }

    /**
     * 注册DelegatingFilterProxy（Shiro）
     *
     * @return
     */
    @Bean
    public FilterRegistrationBean filterRegistrationBean() {
        FilterRegistrationBean filterRegistration = new FilterRegistrationBean();
        filterRegistration.setFilter(new DelegatingFilterProxy("shiroFilter"));
        //  该值缺省为false,表示生命周期由SpringApplicationContext管理,设置为true则表示由ServletContainer管理  
        filterRegistration.addInitParameter("targetFilterLifecycle", "true");
        filterRegistration.setEnabled(true);
        filterRegistration.addUrlPatterns("/*");
        return filterRegistration;
    }

    @Bean(name = "lifecycleBeanPostProcessor")
    public LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() {
        MyShiroRealm realm = new MyShiroRealm();
        realm.setName("myShiroRealm");
        //启用认证缓存，当用户登录一次后将不在查询数据库来获取用户信息，直接在从缓存获取
        realm.setAuthenticationCachingEnabled(true);
        realm.setAuthorizationCachingEnabled(true);
        return new LifecycleBeanPostProcessor();
    }

    @Bean
    public DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator daap = new DefaultAdvisorAutoProxyCreator();
        daap.setProxyTargetClass(true);
        return daap;
    }

    @Bean(name = "securityManager")
    public DefaultWebSecurityManager getDefaultWebSecurityManager(MyShiroRealm myShiroCasRealm) {
        DefaultWebSecurityManager dwsm = new DefaultWebSecurityManager();
        dwsm.setRealm(myShiroCasRealm);
        // 用户授权/认证信息Cache, 采用EhCache 缓存
        dwsm.setCacheManager(getEhCacheManager());
        // 指定 SubjectFactory
        dwsm.setSubjectFactory(new CasSubjectFactory());
        return dwsm;
    }

    @Bean
    public AuthorizationAttributeSourceAdvisor getAuthorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor aasa = new AuthorizationAttributeSourceAdvisor();
        aasa.setSecurityManager(securityManager);
        return aasa;
    }


    /**
     * CAS过滤器
     *
     * @return
     */
    @Bean(name = "casFilter")
    public CasFilter getCasFilter() {
        CasFilter casFilter = new CasFilter();
        casFilter.setName("casFilter");
        casFilter.setEnabled(true);
        // 登录失败后跳转的URL，也就是 Shiro 执行 CasRealm 的 doGetAuthenticationInfo 方法向CasServer验证tiket
        // 选择认证失败后再打开登录页面,也可自定义url
        casFilter.setFailureUrl(loginUrl);
        return casFilter;
    }

    /**
     * ShiroFilter<br/>
     * 注意这里参数中的 StudentService 和 IScoreDao 只是一个例子，因为我们在这里可以用这样的方式获取到相关访问数据库的对象，
     * 然后读取数据库相关配置，配置到 shiroFilterFactoryBean 的访问规则中。实际项目中，请使用自己的Service来处理业务逻辑。
     *
     * @return
     */
    @Bean(name = "shiroFilter")
    public ShiroFilterFactoryBean shiroFilterFactoryBean(DefaultWebSecurityManager securityManager, CasFilter casFilter, ShiroAuthoritySettingRpcService authoritySettingRpcService) {
        logger.info("appCode:" + appCode);
        ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();
        LogoutFilter logoutFilter = new LogoutFilter();
        factoryBean.getFilters().put("casAuthc", casFilter);
        factoryBean.getFilters().put("logout", logoutFilter);
        // 必须设置 SecurityManager  
        factoryBean.setSecurityManager(securityManager);
        // 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面
        factoryBean.setLoginUrl(loginUrl);
        // 登录成功后要跳转的连接
        //factoryBean.setSuccessUrl("/index");
        factoryBean.setUnauthorizedUrl(unauthorizedUrl);
        Map<String, String> filterChainDefinitionMap = new HashMap<>();
        List<ShiroAuthoritySetting> list = authoritySettingRpcService.queryShiroUrlList();
        logger.info("list:" + list);
        for (ShiroAuthoritySetting setting : list) {
            filterChainDefinitionMap.put(setting.getUrl(), setting.getPermissionInit());
        }
        factoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return factoryBean;
    }

}